package org.jeecg.modules.business.transfer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.basic.material.service.IBasicMaterialService;
import org.jeecg.modules.basic.warehouse.mapper.WmsBasicWarehouseMapper;
import org.jeecg.modules.business.repertory.entity.WmsRepertory;
import org.jeecg.modules.business.repertory.entity.vo.RepertoryDocumentVO;
import org.jeecg.modules.business.repertory.entity.vo.RepertoryVO;
import org.jeecg.modules.business.repertory.mapper.WmsRepertoryMapper;
import org.jeecg.modules.business.repertory.service.IWmsRepertoryService;
import org.jeecg.modules.business.transfer.entity.WmsMoveReceipt;
import org.jeecg.modules.business.transfer.entity.WmsMoveReceiptMaterial;
import org.jeecg.modules.business.transfer.mapper.WmsMoveReceiptMapper;
import org.jeecg.modules.business.transfer.mapper.WmsMoveReceiptMaterialMapper;
import org.jeecg.modules.business.transfer.service.IWmsMoveReceiptService;
import org.jeecg.modules.utils.service.CommitService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 移库单
 * @Author: jeecg-boot
 * @Date: 2023-08-11
 * @Version: V1.0
 */
@Service
public class WmsMoveReceiptServiceImpl extends ServiceImpl<WmsMoveReceiptMapper, WmsMoveReceipt> implements IWmsMoveReceiptService {

    @Autowired
    private WmsMoveReceiptMapper wmsMoveReceiptMapper;
    @Autowired
    private WmsMoveReceiptMaterialMapper wmsMoveReceiptMaterialMapper;
    @Autowired
    private WmsRepertoryMapper wmsRepertoryMapper;
    @Autowired
    @Lazy
    private IWmsRepertoryService wmsRepertoryService;
    @Autowired
    private CommitService commitService;
    @Autowired
    @Lazy
    private IWmsRepertoryService iWmsRepertoryService;
    @Autowired
    private WmsBasicWarehouseMapper warehouseMapper;

    @Autowired
    private IBasicMaterialService basicMaterialService;

    private static final String AND = "&";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveMain(WmsMoveReceipt wmsMoveReceipt, List<WmsMoveReceiptMaterial> wmsMoveReceiptMaterialList) {
        long count = this.count(new LambdaQueryWrapper<WmsMoveReceipt>()
                .eq(WmsMoveReceipt::getDocumentCode, wmsMoveReceipt.getDocumentCode()));
        if (count > 0) {
            throw new JeecgBootException(wmsMoveReceipt.getDocumentCode() + "编号的移库单已存在，请勿重复提交");
        }
        // 校验调出储位和调入储位是否一致
        this.checkWarehouse(wmsMoveReceiptMaterialList);
        for (WmsMoveReceiptMaterial material : wmsMoveReceiptMaterialList) {
            BigDecimal transferQuantity = material.getTransferQuantity();
            if (transferQuantity != null && transferQuantity.scale() > 6) {
                throw new JeecgBootException("移库数量小数位数不能超过6位！");
            }
        }

        wmsMoveReceiptMapper.insert(wmsMoveReceipt);
        if (wmsMoveReceiptMaterialList != null && wmsMoveReceiptMaterialList.size() > 0) {
            for (WmsMoveReceiptMaterial entity : wmsMoveReceiptMaterialList) {
                //外键设置
                entity.setWmsMoveReceiptId(wmsMoveReceipt.getId());
                if (StrUtil.isNotEmpty(entity.getMaterialId())){
                    entity.setWmsBasicMaterialId(entity.getMaterialId());
                }
                wmsMoveReceiptMaterialMapper.insert(entity);
                basicMaterialService.updateUsedState(entity.getMaterialId());
            }
        }
//        iWmsRepertoryService.moveSubmit(wmsMoveReceipt.getId());
        return wmsMoveReceipt.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMain(WmsMoveReceipt wmsMoveReceipt, List<WmsMoveReceiptMaterial> wmsMoveReceiptMaterialList) {
        // 校验调出储位和调入储位是否一致
        this.checkWarehouse(wmsMoveReceiptMaterialList);

        for (WmsMoveReceiptMaterial material : wmsMoveReceiptMaterialList) {
            BigDecimal transferQuantity = material.getTransferQuantity();
            if (transferQuantity.scale() > 6) {
                throw new JeecgBootException("移库数量小数位数不能超过6位！");
            }
        }

        wmsMoveReceiptMapper.updateById(wmsMoveReceipt);

        List<WmsMoveReceiptMaterial> materials = wmsMoveReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsMoveReceiptMaterial>()
                .eq(WmsMoveReceiptMaterial::getWmsMoveReceiptId, wmsMoveReceipt.getId()));

        //1.先删除子表数据
        wmsMoveReceiptMaterialMapper.deleteByMainId(wmsMoveReceipt.getId());
        for (WmsMoveReceiptMaterial material : materials) {
            basicMaterialService.updateUsedState(material.getMaterialId());
        }

        //2.子表数据重新插入
        if (wmsMoveReceiptMaterialList != null && wmsMoveReceiptMaterialList.size() > 0) {
            for (WmsMoveReceiptMaterial entity : wmsMoveReceiptMaterialList) {
                //外键设置
                entity.setWmsMoveReceiptId(wmsMoveReceipt.getId());
                wmsMoveReceiptMaterialMapper.insert(entity);
                basicMaterialService.updateUsedState(entity.getMaterialId());
            }
        }
//        iWmsRepertoryService.moveSubmit(wmsMoveReceipt.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delMain(String id) {
        List<WmsMoveReceiptMaterial> materials = wmsMoveReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsMoveReceiptMaterial>()
                .eq(WmsMoveReceiptMaterial::getWmsMoveReceiptId, id));
        wmsMoveReceiptMaterialMapper.deleteByMainId(id);
        wmsMoveReceiptMapper.deleteById(id);
        for (WmsMoveReceiptMaterial material : materials) {
            basicMaterialService.updateUsedState(material.getMaterialId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delBatchMain(Collection<? extends Serializable> idList) {
        for (Serializable id : idList) {
            List<WmsMoveReceiptMaterial> materials = wmsMoveReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsMoveReceiptMaterial>()
                    .eq(WmsMoveReceiptMaterial::getWmsMoveReceiptId, id));
            wmsMoveReceiptMaterialMapper.deleteByMainId(id.toString());
            wmsMoveReceiptMapper.deleteById(id);
            for (WmsMoveReceiptMaterial material : materials) {
                basicMaterialService.updateUsedState(material.getMaterialId());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void commit(String id, HttpServletRequest req) {
        WmsMoveReceipt wmsMoveReceipt = wmsMoveReceiptMapper.selectById(id);
        String warehouseId = wmsMoveReceipt.getTransferFromWarehouseId();
        List<WmsMoveReceiptMaterial> wmsMoveReceiptMaterials = wmsMoveReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsMoveReceiptMaterial>()
                .eq(WmsMoveReceiptMaterial::getWmsMoveReceiptId, id));
        Map<String, BigDecimal> map = wmsMoveReceiptMaterials.stream()
                .collect(Collectors.groupingBy(o -> o.getWmsBasicMaterialId() + AND + o.getTransferFromAreaId() + AND + o.getTransferFromLocationId(),
                        Collectors.mapping(WmsMoveReceiptMaterial::getTransferQuantity, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            String[] split = next.split(AND);
            LambdaQueryWrapper<WmsRepertory> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(WmsRepertory::getWmsBasicWarehouseId,warehouseId);
            for (int i = 0; i < split.length; i++) {
                if (StrUtil.isEmpty(split[i]) && i == 0) {
                    wrapper.eq(WmsRepertory::getMaterialId, split[i]);
                }
                if (StrUtil.isEmpty(split[i]) && i == 1) {
                    wrapper.eq(WmsRepertory::getWmsBasicWarehouseAreaId, split[i]);
                }
                if (StrUtil.isEmpty(split[i]) && i == 2) {
                    wrapper.eq(WmsRepertory::getWmsBasicWarehouseAreaLocationId, split[i]);
                }
            }
            List<WmsRepertory> wmsRepertories = wmsRepertoryMapper.selectList(wrapper);
            if (CollectionUtil.isEmpty(wmsRepertories)) {
                throw new JeecgBootException("当前物料无实时库存");
            }
            if (wmsRepertories.size() > 1) {
                throw new JeecgBootException("根据物料、仓库、库区和库位查询到[" + wmsRepertories.get(0).getMaterialName() + "]多条实时库存");
            }
            WmsRepertory wmsRepertory = wmsRepertories.get(0);
            if (wmsRepertory.getStockQuantity().compareTo(map.get(next)) < 0) {
                throw new JeecgBootException("该物料在当前存放地的库存数量小于出库数量，不可移库");
            }
        }
        commitService.sendMessage(id, req);
    }

    /**
     * 移库更新实时库存
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveRepertory(String id) {
        // 移库校验
        wmsRepertoryService.moveSubmit(id);

        List<WmsMoveReceiptMaterial> wmsMoveReceiptMaterialList = wmsMoveReceiptMaterialMapper.selectList(new LambdaQueryWrapper<WmsMoveReceiptMaterial>()
                .eq(WmsMoveReceiptMaterial::getWmsMoveReceiptId, id));
        WmsMoveReceipt move = this.getById(id);
        if(StrUtil.isEmpty(move.getTransferFromWarehouseId())){
            throw new JeecgBootException("没有仓库信息");
        }
        // 减少即时库存
        List<RepertoryVO> reduceRepertoryList = wmsMoveReceiptMaterialList.stream().map(o -> {
            RepertoryVO repertoryVO = BeanUtil.copyProperties(o, RepertoryVO.class);
            repertoryVO.setWmsBasicWarehouseId(move.getTransferFromWarehouseId());
            repertoryVO.setWmsBasicWarehouseAreaId(o.getTransferFromAreaId());
            repertoryVO.setWmsBasicWarehouseAreaLocationId(o.getTransferFromLocationId());
            repertoryVO.setStockQuantity(o.getTransferQuantity());
            repertoryVO.setBatchCode(o.getBatchCode());
            repertoryVO.setStockQuantitySub(o.getAssistQuantity());
            return repertoryVO;
        }).collect(Collectors.toList());
        RepertoryDocumentVO repertoryDocumentVO = new RepertoryDocumentVO();
        repertoryDocumentVO.setInvoicesId(id);
        repertoryDocumentVO.setDocumentType(3);
        repertoryDocumentVO.setRepertoryVOS(reduceRepertoryList);
        //扣除即时库存
        wmsRepertoryService.reduce(repertoryDocumentVO);

        //增加即时库存
        List<RepertoryVO> addRepertoryList = wmsMoveReceiptMaterialList.stream().map(o -> {
            RepertoryVO repertoryVO = BeanUtil.toBean(o, RepertoryVO.class);
            repertoryVO.setWmsBasicWarehouseId(move.getTransferFromWarehouseId());
            repertoryVO.setWmsBasicWarehouseAreaId(o.getTransferToAreaId());
            repertoryVO.setWmsBasicWarehouseAreaLocationId(o.getTransferToLocationId());
            repertoryVO.setWmsBasicMaterialId(o.getWmsBasicMaterialId());
            repertoryVO.setStockQuantity(o.getTransferQuantity());
            repertoryVO.setBatchCode(o.getBatchCode());
            repertoryVO.setStockQuantitySub(o.getAssistQuantity());
            if (StringUtils.isNotBlank(o.getRepertoryId())) {
                WmsRepertory repertory = wmsRepertoryService.getById(o.getRepertoryId());
                repertoryVO.setWmsBasicSupplierId(Objects.isNull(repertory) ? null : repertory.getWmsBasicSupplierId());
                repertoryVO.setSupplier(Objects.isNull(repertory) ? null : repertory.getSupplier());
            }
            return repertoryVO;
        }).collect(Collectors.toList());
        RepertoryDocumentVO repertoryDocumentVOS = new RepertoryDocumentVO();
        repertoryDocumentVOS.setDocumentType(3);
        repertoryDocumentVOS.setInvoicesId(id);
        repertoryDocumentVOS.setRepertoryVOS(addRepertoryList);
        //增加库存
        wmsRepertoryService.add(repertoryDocumentVOS);
    }

    /**
     * 分页
     * @param page
     * @param moveReceipt
     * @return
     */
    @Override
    public Page<WmsMoveReceipt> listByPage(Page<WmsMoveReceipt> page, WmsMoveReceipt moveReceipt) {
        return page.setRecords(wmsMoveReceiptMapper.listByPage(page, moveReceipt));
    }

    /**
     * 校验调出和调入的储位
     */
    private void checkWarehouse(List<WmsMoveReceiptMaterial> list) {
        for (WmsMoveReceiptMaterial material : list) {
            if (StringUtils.isBlank(material.getTransferFromAreaId())) {
                material.setTransferFromAreaId(null);
            }
            if (StringUtils.isBlank(material.getTransferFromLocationId())) {
                material.setTransferFromLocationId(null);
            }
            if (StringUtils.isBlank(material.getTransferToAreaId())) {
                material.setTransferToAreaId(null);
            }
            if (StringUtils.isBlank(material.getTransferToLocationId())) {
                material.setTransferToLocationId(null);
            }
            if (StringUtils.isBlank(material.getTransferFromAreaId()) && StringUtils.isBlank(material.getTransferToAreaId())
                && StringUtils.isBlank(material.getTransferFromLocationId()) && StringUtils.isBlank(material.getTransferToLocationId())) {
                throw new JeecgBootException("调出储位不可跟调入储位一致！");
            }
            if (ObjectUtil.equal(material.getTransferFromAreaId(), material.getTransferToAreaId())
                && ObjectUtil.equal(material.getTransferFromLocationId(), material.getTransferToLocationId())) {
                throw new JeecgBootException("调出储位不可跟调入储位一致！");
            }
        }
    }
}
